render hooks pattern
Custom Hook から Component を返却する render hooks パターンの場合、返却された Component がアンマウントされてしまうことによりバグが発生する恐れがあるので注意が必要です。
Custom Hook から Component を返さずに React element を返す実装にすれば、 アンマウントを回避できます。
componentは含めないのか
ロジックとcomponentが明らかに凝集している、という場合に有用
ModalというComponentを返している
code:ts
const App = () => {
preventScroll: true,
closeOnOverlayClick: false
});
return (
<div>
<p>Modal is Open? {isOpen ? 'Yes' : 'No'}</p>
<button onClick={open}>OPEN</button>
<Modal>
<div>
<h1>Title</h1>
<p>This is a customizable modal.</p>
<button onClick={close}>CLOSE</button>
</div>
</Modal>
</div>
);
};
実装箇所
useCallback使ってる
うまく動かない例
code:ts
const useForm = () => {
const Field: React.FC = useCallback(
() => <input value={value} onChange={e => setValue(e.target.value)} />,
);
return {
Field,
};
};
値が入力されるたびにFieldが新しく作られるので、1文字入力するたびにフォーカスが外れてしまう
https://gyazo.com/7831821d2cf02d14c5a15793d777bac5
どうしてもこういうAPIを提供したいならuseRef使ってハックっぽくするとか
code:ts
const useForm = () => {
const valueRef = useRef('');
const Field: React.FC = () => {
const inputRef = useRef<HTMLInputElement | null>(null);
useEffect(() => {
if (inputRef.current) {
inputRef.current.value = valueRef.current;
}
}, []);
const onChange = (e: React.ChangeEvent<HTMLInputElement>) => {
valueRef.current = e.target.value;
};
return <input ref={inputRef} onChange={onChange} />;
};
return {
Field,
};
};
ちなみにこうかくとめちゃくちゃバグる
code:ts
const useForm = () => {
const ref = useRef(value);
useEffect(() => {
ref.current = value;
const Field: React.FC = useCallback(
() => (
<input value={ref.current} onChange={(e) => setValue(e.target.value)} />
),
[]
);
return {
Field,
};
};